package com.lagou.server;

import com.lagou.handler.UserServerHandler;
import com.lagou.service.JSONSerializer;
import com.lagou.service.RpcDecoder;
import com.lagou.service.RpcRequest;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringEncoder;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Component
public class StartServer implements ApplicationContextAware {

    @Value("${rpc.server.port}")
    private Integer serverPort;

    private static ApplicationContext applicationContext2;

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        applicationContext2 = applicationContext;
    }

    @PostConstruct
    public void start() throws Exception {
        startServer("127.0.0.1",null);
    }

    //hostName:ip地址  port:端口号
    public void startServer(String hostName,Integer port) throws Exception {
        if (null != port){
            serverPort = port;
        }

        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup,workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(new StringEncoder());
                        pipeline.addLast( new RpcDecoder(RpcRequest.class, new JSONSerializer()));
                        pipeline.addLast(new UserServerHandler());

                    }
                });
        serverBootstrap.bind(hostName,serverPort).sync();
        System.out.println("服务启动");

        register(hostName,serverPort);

    }

    public void register(String host,Integer port) throws Exception {
        Map<String, Object> beansWithAnnotation = applicationContext2.getBeansWithAnnotation(Service.class);;
        Set<String> providers = beansWithAnnotation.values().stream()
                .map(obj -> obj.getClass().getInterfaces())
                .flatMap(Arrays::stream).map(inf -> {
                    StringBuilder builder = new StringBuilder("/rpc/");
                    return builder.append(inf.getName())
                            .append("/providers/")
                            .append(host)
                            .append(":")
                            .append(port).toString();

                }).collect(Collectors.toSet());

        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);

        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString(host+":"+2181)
                .sessionTimeoutMs(5000)
                .connectionTimeoutMs(3000)
                .retryPolicy(retryPolicy)
                .build();
        client.start();

        for (String provider : providers) {
            client.create().creatingParentsIfNeeded().
                    withMode(CreateMode.EPHEMERAL).forPath(provider,"0".getBytes());
        }

        System.out.println("服务已经注册");
    }

}